using System.Collections.Generic;
using System.Diagnostics;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using TechNewLogic.GraphIT.Helper;

namespace TechNewLogic.GraphIT.Drawing
{
	class TestDrawer : IDrawer
	{
		public HitTester DrawLine(
			double thickness,
			IEnumerable<IList<Point>> points,
			int width,
			int height,
			out byte[] bitmap,
			out byte[] selection)
		{
			var stride = MathHelper.GetStride(width, 32);

			bitmap = new byte[stride * height];
			selection = new byte[stride * height];

			//DrawLineFast(bitmap, 0, 0, width, height, width);
			DrawLineDDA(bitmap, 0, 0, width, height, width, height);

			//for (int w = 0; w < width; w++)
			//{
			//    for (int h = 0; h < height; h++)
			//    {
			//        if (w == h)
			//        {
			//            //intBuffer[w * h] = 1;
			//            var i = w * h;
			//            bitmap[i] = 255;
			//        }
			//    }
			//}

			return new HitTester(bitmap, stride);
		}

		public static void DrawLineDDA(byte[] pixels, int x1, int y1, int x2, int y2, int width, int height)
		{
			// Distance start and end point
			int dx = x2 - x1;
			int dy = y2 - y1;

			// Determine slope (absoulte value)
			int len = dy >= 0 ? dy : -dy;
			int lenx = dx >= 0 ? dx : -dx;
			if (lenx > len)
			{
				len = lenx;
			}

			// Prevent divison by zero
			if (len != 0)
			{
				// Init steps and start
				float incx = dx / (float)len;
				float incy = dy / (float)len;
				float x = x1;
				float y = y1;

				// Walk the line!
				for (int i = 0; i < len; i++)
				{
					if (y < height && y >= 0 && x < width && x >= 0)
					{
						pixels[(int)y * width + (int)x] = 255;
					}
					x += incx;
					y += incy;
				}
			}
		}

		public static void DrawLineFast(byte[] pixels, int x1, int y1, int x2, int y2, int width)
		{
			// Distance start and end point
			int dx = x2 - x1;
			int dy = y2 - y1;

			const int PRECISION_SHIFT = 8;
			const int PRECISION_VALUE = 1 << PRECISION_SHIFT;

			// Determine slope (absoulte value)
			int lenX, lenY;
			int incy1;
			if (dy >= 0)
			{
				incy1 = PRECISION_VALUE;
				lenY = dy;
			}
			else
			{
				incy1 = -PRECISION_VALUE;
				lenY = -dy;
			}

			int incx1;
			if (dx >= 0)
			{
				incx1 = 1;
				lenX = dx;
			}
			else
			{
				incx1 = -1;
				lenX = -dx;
			}

			if (lenX > lenY)
			{
				// x increases by +/- 1

				// Init steps and start
				int incy = (dy << PRECISION_SHIFT) / lenX;
				int y = y1 << PRECISION_SHIFT;

				// Walk the line!
				for (int i = 0; i < lenX; i++)
				{
					pixels[(y >> PRECISION_SHIFT) * width + x1] = 1;
					x1 += incx1;
					y += incy;
				}
			}
			else
			{
				// since y increases by +/-1, we can safely add (*h) before the for() loop, since there is no fractional value for y
				// Prevent divison by zero
				if (lenY == 0)
				{
					return;
				}

				// Init steps and start
				int incx = (dx << PRECISION_SHIFT) / lenY;
				int index = (x1 + y1 * width) << PRECISION_SHIFT;

				// Walk the line!
				int inc = incy1 * width + incx;
				for (int i = 0; i < lenY; i++)
				{
					pixels[index >> PRECISION_SHIFT] = 1;
					index += inc;
				}
			}
		}
	}
}